Day 08 瘦身完的檔案還不能出貨,這一站要做的事,由 web-pack 這個工班負責——它是整條生產線裡唯一被允許做座標轉換的一站,之前每一步都刻意不轉,就是為了留到這裡一次做完。
web-pack 是用 JavaScript 寫的,底層借用一套開源的工具箱叫 glTF Transform:專門用來「打開 GLB 包裹、動手整理、再重新封起來」。你可以把它想成一組整理包裹用的工具,分成幾個抽屜:一個負責打開與封起包裹(讀寫),一個負責認得各種特殊封裝方式(例如真空壓縮),一個放著現成的整理動作(去重複、丟垃圾、壓縮),另外還附一個給人在命令列下指令用的遙控器。這些抽屜是同一個團隊出的,版本要一起對,不能混搭。
輸入 GLB
→ dedup + prune(去掉重複與沒用到的資料)
→ (--yup)Z-up mm → Y-up m
→ (--draco)Draco 幾何壓縮
→ 寫檔
dedup 是把重複放了兩份、內容一模一樣的東西合併成一份(例如兩份一樣的材質說明);prune 是把已經沒有任何零件在用的東西直接丟掉(例如某個沒人引用的空盒子)。這一步只讓包裹更精簡,不改變任何看得見的東西。--yup 開關):只有在「要出貨」時才打開這個開關。詳見下一節。--draco 開關):用專門的壓縮技術把形狀資料再壓縮一次,也是一個可選的開關。Day 05 提過,我們內部的「地圖」跟瀏覽器習慣的「地圖」,對哪邊是「上」定義不同:我們內部(跟 CAD 軟體一樣)用 Z 軸當「上」,瀏覽器的 3D 世界(glTF 的規定)用 Y 軸當「上」。為什麼是 Y 或 Z?沒有什麼數學上的理由,純粹是兩個圈子各自的習慣:做工程、CAD 的圈子習慣 Z 朝上,做遊戲、網頁 3D 的圈子習慣 Y 朝上。三個軸裡只有這兩派,沒有人用 X 當「上」。另外,我們內部用公釐量長度,瀏覽器習慣用公尺,這裡也一併換算。
做法很巧妙:不去搬動包裹裡的任何一件東西,而是在整個場景外面多包一層「轉接殼」(技術上是一個新的根節點,名字叫 YUP_ROOT),殼上記著「整體縮小一千倍、轉個方向」的規則。因為只動最外層,零件的名字、階層、相對位置完全不受影響——這也是為什麼可以放心把它排在瘦身之後才做:不會把 Day 07、08 辛苦保住的零件樹弄亂。
這個動作在程式裡拆成兩個小函式:
yUpMillimetersToMetersMatrix(矩陣計算):寫「轉接殼上的那張說明書」——把「縮小一千倍」和「轉個方向」兩件事,濃縮成一組數字(矩陣)。它只負責算出這張說明書,不動任何東西。applyYupConversion(動手包殼):真正動手的函式。它把場景裡原本最外層的東西全部收進新的轉接殼底下,把上面那張說明書貼上去,最後再貼一張標籤(見下一節)。包裹外殼上會貼一張標籤,寫著「這箱已經轉成公尺、Y 朝上」(expo3d_unit、expo3d_up_axis 兩行字)。
為什麼只有轉過才貼?因為這張標籤等於一句聲明。如果沒轉方向(例如只是想先看看瘦身效果)卻貼了「已轉換」,就是謊報,下游會把一箱其實還是公釐、Z 朝上的東西誤當成標準品。所以沒轉,就完全不貼,連一張空白標籤都不貼。
這張標籤要特別分清楚,因為系統裡有兩個名字很像、卻完全不同的東西:
asset.extras):住在包裹裡面,誰拿到這個包裹都看得到——不需要另外的文件。單位這種「一拿到包裹就必須知道」的資訊,屬於這一類。asset.json,裡面也有一個叫 extras 的欄位):這是放在包裹旁邊的另一份文件,記錄零件清單、預算、品質報告等等。它的 extras 欄位是留給各個「場景包」(例如機械、展場)放自己專屬資料的地方,鍵是場景包的名字。簡單說:要跟著包裹一起走的資訊,貼在包裹上;只是專案內部、或某個場景包自己的私有資料,放在旁邊的履歷表。
拿 Day 06 的減速機實測:這台機器先經過 Day 07 的 cad-ingest(把 STEP 食譜轉成 GLB 包裹)、再經過 Day 08 的 mesh-forge(打掃加瘦身),瘦身完的檔案 86,540 位元組,真空封裝完剩 17,296 位元組,縮到約五分之一。
出貨前還有兩件事,也各自是一個函式:
measureBudget(過磅點數):把包裹點數一遍——三角形有幾個、要分幾次畫、貼圖最大多大、整個檔案幾位元組——記下來,之後才能對照預算,看有沒有超標。runValidator(海關檢查):把包裹交給官方的檢驗工具,逐項核對格式合不合規,回報「幾個錯誤、幾個警告、幾個提示」。這是一道硬關卡,過不了就不能出貨。實測結果:零錯誤、零警告,18 個節點名稱(17 個零件 + 轉接殼)全部保留。貼圖壓縮的介面已經留了,但目前範例模型沒有貼圖,還沒真的接上實作——先把「形狀怎麼壓縮」這件事做穩,貼圖壓縮之後再補。
下一篇會直接打開瀏覽器,看看這箱轉了老半天的包裹長什麼樣。